/*
 ***************************************************************************
 * MediaTeK Inc.
 * 4F, No. 2 Technology	5th	Rd.
 * Science-based Industrial	Park
 * Hsin-chu, Taiwan, R.O.C.
 *
 * (c) Copyright 2002-2012, MTK.
 *
 * All rights reserved.	MediaTeK's source	code is	an unpublished work	and	the
 * use of a	copyright notice does not imply	otherwise. This	source code
 * contains	confidential trade secret material of MediaTeK Tech. Any attemp
 * or participation	in deciphering,	decoding, reverse engineering or in	any
 * way altering	the	source code	is stricitly prohibited, unless	the	prior
 * written consent of MediaTeK, Inc. is obtained.
 ***************************************************************************

	Module Name:
	omci_me_private_fuc.c

	Abstract:

	Revision History:
	Who			When			What
	--------	----------		----------------------------------------------
	Name		Date			Modification logs
	mingang.tan	2018/8/16	Create
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "errno.h"
#include "omci_adpt_common.h"
#include "omci_adpt_general.h"
#include "omci_external_msg.h"


#ifdef TCSUPPORT_PON_ROSTELECOM 

#define OMCI_UPLOAD_CONFIG  "/tmp/upload_config" 	// path for Huawei config upload

extern uint8_t weWindowSize;
extern uint8_t windowSize;
extern downloadImage_t downloadImageBuffer;
extern uint16_t downloadImageNum;
extern int tmrIdImage;
extern uint8_t writeImageToFlash;
extern int tmrIdSecMiss;
extern int sectionMiss;
extern uint8_t gSectionNumber;
extern short gTranCorrelatId;
extern int downSecNumInAWindow;
extern int nextNewWindowFlag;
extern downloadWindow_t swWindow_global;

extern int omciCheckSwWindow(void);
extern int omciDataSyncSeqIncret(void);
extern int omciSwDownloadTimeout(downloadImage_t *dowloadImage );
extern int omciSwDownloadSecMissTimeout(omciGenericPayload_t * omciPayLoad );
extern int omciAddSectionToWindow(downloadWindow_t *swWindow_ptr, uint8_t *data , uint8_t sectionNum, uint16_t sectionSize,uint16_t devId);
extern uint32_t compute_crc32_big_endian(char *path);
extern void reset_upgrade_global_resources(void);

int omciHuaweiConfigStartDownloadAction(uint16_t meClassId , omciMeInst_t *meInstant_ptr, omciGenericPayload_t * omciPayLoad, uint8_t msgSrc)
{
	uint8_t *contentPtr = NULL;
	uint8_t *responseContentPtr = NULL;
	uint8_t resultAndResean = 0;
	uint16_t instanceId=0;
	uint16_t contLen=0;
	uint32_t imageSize = 0;
	uint8_t devId = 0;

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] enter\n", __FUNCTION__, __LINE__);
  	if(omciPayLoad == NULL){
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d] omciPayLoad is NULL!\n", __FUNCTION__, __LINE__);
		return OMCI_CMD_ERROR;
	}

	devId = omciPayLoad->devId;
	contentPtr = (uint8_t *)(omciPayLoad->msgContent);

	instanceId = get16((uint8_t*)&(omciPayLoad->meId)+2);
	if(instanceId > 1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: Software image only two instance \n",__FUNCTION__,__LINE__);
		return OMCI_CMD_ERROR;
	}

	windowSize = *contentPtr;
	imageSize = get32(contentPtr + 1);

	downloadImageBuffer.totalSize = imageSize;
	downloadImageBuffer.currentSize = 0;
	
	/*we should start a timer for download software*/
	downloadImageNum = instanceId;	
	if(tmrIdImage > 0)
		timerStopS(tmrIdImage);

	tmrIdImage= timerStartS(1*TIMER_COUNT_MIN, (TimerCallback)omciSwDownloadTimeout , &downloadImageBuffer);
	if(tmrIdImage == -1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: timerStartS fail!\n",__FUNCTION__,__LINE__);
		return OMCI_CMD_ERROR;
	}

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] downloadImageBuffer.totalSize=%d\n", __FUNCTION__, __LINE__,downloadImageBuffer.totalSize);

	resultAndResean =OMCI_CMD_SUCCESS;
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: command processing success\n",__FUNCTION__,__LINE__);


	/********pkt send*****************/			

	omciDataSyncSeqIncret();

	omciPayLoad->msgType = omciPayLoad->msgType | 0x20; /*AK 6'bit is 1*/
	omciPayLoad->msgType = omciPayLoad->msgType & 0xBF;/*AR 7'bit is 0*/

	responseContentPtr = contentPtr;
	contLen = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : (omciPayLoad->msgContentLength+4);
  	if(contLen > OMCI_EXTENDED_MSG_CONT_LEN)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: contLen=%d is cross the border\n",__FUNCTION__,__LINE__,contLen);
		return OMCI_CMD_ERROR;
	}
	memset(responseContentPtr, 0, contLen);
	*responseContentPtr = resultAndResean;
	omciPayLoad->msgContentLength = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : 2; // 1 bytes for resultAndReseason,1 byte for sec num

	/*write window size*/
	responseContentPtr = contentPtr + 1;
	*responseContentPtr = (weWindowSize == 31 && windowSize < 32)  ? windowSize : weWindowSize;
	
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: omciDumpPkt!weWindowSize = %d\n",__FUNCTION__,__LINE__, weWindowSize);				
	omciPktSend(omciPayLoad, TRUE);
	omciDumpPkt(omciPayLoad);
	
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] return\n", __FUNCTION__, __LINE__);

	return 0;
}

int omciHuaweiConfigDownloadSecAction(uint16_t meClassId , omciMeInst_t *meInstant_ptr, omciGenericPayload_t * omciPayLoad, uint8_t msgSrc)
{
	uint8_t *contentPtr = NULL;
	uint8_t *responseContentPtr = NULL;
	uint8_t resultAndResean = 0;
	uint16_t instanceId=0;
	uint8_t secNum = 0;
	int reval=0;
	int remainSize=0;
	uint8_t devId = 0;
	uint16_t imageDataLen = 0; 
	uint16_t contLen=0;
	FILE *fp = NULL;
	downloadSection_t *swSectionPtr = NULL;

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] enter \n", __FUNCTION__, __LINE__);
  	if(omciPayLoad == NULL){
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d] omciPayLoad is NULL!\n", __FUNCTION__, __LINE__);
		return OMCI_CMD_ERROR;
	}
  

	devId = omciPayLoad->devId;
	contentPtr = (uint8_t *)(omciPayLoad->msgContent);
	imageDataLen = (devId == OMCI_BASELINE_MSG) ? (OMCI_BASELINE_CONT_LEN - 1) : (omciPayLoad->msgContentLength - 1);

	instanceId = get16((uint8_t*)&(omciPayLoad->meId)+2);
	if(instanceId > 1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: Software image only two instance \n",__FUNCTION__,__LINE__);
		return OMCI_CMD_ERROR;
	}

	secNum = (uint8_t)(*contentPtr);
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: secNum = %d\n",__FUNCTION__,__LINE__, secNum);

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] secNum = %d \n", __FUNCTION__, __LINE__,secNum);

	if(nextNewWindowFlag == 1)
	{
		memset(&swWindow_global, 0, sizeof(downloadWindow_t));
		downSecNumInAWindow = 1;
		nextNewWindowFlag = 0;
	}
	else
	{
		downSecNumInAWindow++;
	}
	
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] nextNewWindowFlag=%d,downSecNumInAWindow=%d\n",
		__FUNCTION__, __LINE__,nextNewWindowFlag,downSecNumInAWindow);

	remainSize = downloadImageBuffer.totalSize - downloadImageBuffer.currentSize;
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: remainSize = 0x%lx\n",__FUNCTION__,__LINE__, remainSize);
	if(remainSize >= imageDataLen)	
	{
		reval = omciAddSectionToWindow(contentPtr+1, secNum, imageDataLen,devId);
	}
	else
	{
		reval = omciAddSectionToWindow(contentPtr+1, secNum, remainSize,devId);
	}
	if(reval == -1)
	{
		resultAndResean = OMCI_CMD_ERROR;
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: command processing error\n",__FUNCTION__,__LINE__);
		
		return OMCI_CMD_ERROR;
	}
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: omciAddSectionToWindow success\n",__FUNCTION__,__LINE__);

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] \n", __FUNCTION__, __LINE__);

	if(tmrIdImage > 0)
	{
		timerStopS(tmrIdImage);
	}
	tmrIdImage= timerStartS(1*TIMER_COUNT_MIN, (TimerCallback)omciSwDownloadTimeout , &downloadImageBuffer);
	if(tmrIdImage == -1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: timerStartS fail!\n");
		return -1;
	}
	
	if((omciPayLoad->msgType & DOWNLOAD_SEC_AR) == 0)	
	{
		if (sectionMiss == 0){
			omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: section download success, no response expected!\n",__FUNCTION__,__LINE__);			
			return 0;
		}
	}
	else {
		gTranCorrelatId = omciPayLoad->tranCorrelatId;
		gSectionNumber = secNum;
	}
	//omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: window %d download success, response expected!windowsize = %d\n",__FUNCTION__,__LINE__,downloadImageBuffer.currentWindowPtr->windowNum, downSecNumInAWindow);			

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] download success\n", __FUNCTION__, __LINE__);

	if(tmrIdSecMiss > 0)
	{
		timerStopS(tmrIdSecMiss);
		tmrIdSecMiss = 0;
	}
	tmrIdImage= timerStartS(1*TIMER_COUNT_MIN, (TimerCallback)omciSwDownloadTimeout , &downloadImageBuffer);
	if(tmrIdSecMiss == -1)
		{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d]: Section miss timeout!\n",__FUNCTION__,__LINE__);
		return -1;
		}
	if(omciCheckSwWindow() == -1)
	{
		sectionMiss = 1;
		omcidbgPrintf(OMCI_DEBUG_LEVEL_WARN, "[%s][%d]: section miss!!\n",__FUNCTION__,__LINE__);			
		return 0;
	}

	fp = fopen(OMCI_UPLOAD_CONFIG, "a+");
    if(fp == NULL)
    {
        omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "open OMCI_UPLOAD_FW FILE fail!\n");
        return OMCI_CMD_ERROR;
    }
    omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "fopen OMCI_UPLOAD_FW FILE success!\n");
    
    swSectionPtr = swWindow_global.sectionList_p;
    while(swSectionPtr != NULL)
    {
        fwrite(swSectionPtr->secContent, sizeof(uint8_t), swSectionPtr->secLength, fp);
        swSectionPtr = swSectionPtr->nextSection;
    }
    fclose(fp);
    omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "fwrite OMCI_UPLOAD_FW FILE success!\n");
	
	resultAndResean =OMCI_CMD_SUCCESS;
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: command processing success\n",__FUNCTION__,__LINE__);			

	/********pkt send*****************/
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] pkt send\n", __FUNCTION__, __LINE__);


	omciPayLoad->msgType = omciPayLoad->msgType | 0x20; /*AK 6'bit is 1*/
	omciPayLoad->msgType = omciPayLoad->msgType & 0xBF;/*AR 7'bit is 0*/

	responseContentPtr = contentPtr;
	contLen = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : (omciPayLoad->msgContentLength+4);
  	if(contLen > OMCI_EXTENDED_MSG_CONT_LEN)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: contLen=%d is cross the border\n",__FUNCTION__,__LINE__,contLen);
		return OMCI_CMD_ERROR;
	}
	memset(responseContentPtr, 0, contLen);
	*responseContentPtr = resultAndResean;
	omciPayLoad->msgContentLength = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : 2; // 1 bytes for resultAndReseason,1 byte for sec num


	/*write download section number*/
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: reason=%d,sectionMiss:%d!\n",__FUNCTION__,__LINE__,resultAndResean,sectionMiss);
	responseContentPtr = contentPtr + 1;
	if ((resultAndResean == OMCI_CMD_SUCCESS) && (sectionMiss > 0)) {
		omciPayLoad->tranCorrelatId = gTranCorrelatId;
		*responseContentPtr = gSectionNumber;
	}
	else
		*responseContentPtr = secNum;

	sectionMiss = 0;
	nextNewWindowFlag = 1;
	if(tmrIdSecMiss > 0)
	{
		timerStopS(tmrIdSecMiss);
		tmrIdSecMiss = 0;
	}

	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: omciDumpPkt!\n",__FUNCTION__,__LINE__); 		
	omciPktSend(omciPayLoad, TRUE);
	omciDumpPkt(omciPayLoad);

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] return \n", __FUNCTION__, __LINE__);
	return 0;		
}

int omciHuaweiConfigEndDownloadAction(uint16_t meClassId , omciMeInst_t *meInstant_ptr, omciGenericPayload_t * omciPayLoad, uint8_t msgSrc)
{
	uint8_t *contentPtr = NULL;
	uint8_t *responseContentPtr = NULL;
	uint8_t resultAndResean = 0;
	uint16_t instanceId=0;
	downloadSection_t *swSectionPtr = NULL;
	downloadWindow_t *swWindowPtr = NULL;
	downloadWindow_t *tmpSwWindowPtr = NULL;
	uint32_t crc32_OLT = 0;
	uint32_t crc32_ONU = 0;
	uint32_t imageSize = 0;
	FILE *fp=NULL;
	uint8_t devId = 0;
	uint16_t contLen=0;

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD]\n", __FUNCTION__, __LINE__);
  	if(omciPayLoad == NULL){
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d] omciPayLoad is NULL!\n", __FUNCTION__, __LINE__);
		return OMCI_CMD_ERROR;
	}
  
	devId = omciPayLoad->devId;
	contentPtr = (uint8_t *)(omciPayLoad->msgContent);

	instanceId = get16((uint8_t*)&(omciPayLoad->meId)+2);
	if(instanceId > 1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: Software image only two instance \n",__FUNCTION__,__LINE__);
		return OMCI_CMD_ERROR;
	}

	crc32_OLT =get32(contentPtr);
	imageSize =get32(contentPtr+4);

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] crc32_OLT=%x, imageSize=%d\n", __FUNCTION__, __LINE__,crc32_OLT,imageSize);	
	
	/****************************************************************
	copy download image from downloadImageBuffer to writeBuffer,
	do crc32 check upon download image, if crc32 is OK, send end download success 
	response to OLT.
	****************************************************************/
	if(imageSize != downloadImageBuffer.totalSize)
	{
		resultAndResean = OMCI_CMD_ERROR;
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: image size error!\n",__FUNCTION__,__LINE__); 			
		return OMCI_CMD_ERROR;		
	}
	swWindowPtr = downloadImageBuffer.windowList;
    crc32_ONU = compute_crc32_big_endian(OMCI_UPLOAD_CONFIG);  
    if(crc32_ONU != crc32_OLT){
        omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR,"[%s][%d] crc check Error!!! crc32_OLT=0x%lx, crc32_ONU=0x%lx\n",__FUNCTION__,__LINE__,crc32_OLT,crc32_ONU);
        return OMCI_CMD_ERROR;
    }

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] crc check success\n", __FUNCTION__, __LINE__);
	
	reset_upgrade_global_resources();
	downloadImageBuffer.totalSize = 0;
	downloadImageBuffer.currentSize = 0;
	if(tmrIdImage > 0)
	{
		timerStopS(tmrIdImage);
		tmrIdImage = 0;
	}

	resultAndResean = OMCI_CMD_SUCCESS;
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] OMCI_CMD_SUCCESS\n", __FUNCTION__, __LINE__);


	/********pkt send*****************/	
	omciDataSyncSeqIncret();

	omciPayLoad->msgType = omciPayLoad->msgType | 0x20; /*AK 6'bit is 1*/
	omciPayLoad->msgType = omciPayLoad->msgType & 0xBF;/*AR 7'bit is 0*/

	responseContentPtr = contentPtr;
	contLen = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : (omciPayLoad->msgContentLength+4);
  	if(contLen > OMCI_EXTENDED_MSG_CONT_LEN)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: contLen=%d is cross the border\n",__FUNCTION__,__LINE__,contLen);
		return OMCI_CMD_ERROR;
	}
	memset(responseContentPtr, 0, contLen);
	*responseContentPtr = resultAndResean;
	omciPayLoad->msgContentLength = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : 1;// 1 byte for resultAndReason
		
	omciPktSend(omciPayLoad, TRUE);
	omciDumpPkt(omciPayLoad);	

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] return\n", __FUNCTION__, __LINE__);	
	return 0;		

}

int omciHuaweiConfigCommitAction(uint16_t meClassId , omciMeInst_t *meInstant_ptr, omciGenericPayload_t * omciPayLoad, uint8_t msgSrc)
{
	uint8_t *contentPtr = NULL;
	uint8_t *responseContentPtr = NULL;
	uint8_t resultAndResean = 0;
	uint16_t instanceId=0;
	uint8_t devId = 0;
	uint16_t contLen=0;

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] enter\n", __FUNCTION__, __LINE__);
  	if(omciPayLoad == NULL){
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d] omciPayLoad is NULL!\n", __FUNCTION__, __LINE__);
		return OMCI_CMD_ERROR;
	}
  
	devId = omciPayLoad->devId;
	contentPtr = (uint8_t *)(omciPayLoad->msgContent);

	
	instanceId = get16((uint8_t*)&(omciPayLoad->meId)+2);
	if(instanceId > 1)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: Software image only two instance \n",__FUNCTION__,__LINE__);
		return OMCI_CMD_ERROR;
	}


	/****************************************************************
	Start executing the config file here
	****************************************************************/
	
	omcidbgPrintf(OMCI_DEBUG_LEVEL_TRACE, "[%s][%d]: do nothing\n");
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] \n", __FUNCTION__, __LINE__);

	/********pkt send*****************/ 
	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] pkt send\n", __FUNCTION__, __LINE__);

	omciDataSyncSeqIncret();

	omciPayLoad->msgType = omciPayLoad->msgType | 0x20; /*AK 6'bit is 1*/
	omciPayLoad->msgType = omciPayLoad->msgType & 0xBF;/*AR 7'bit is 0*/

	responseContentPtr = contentPtr;
	contLen = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : (omciPayLoad->msgContentLength+4);
  	if(contLen > OMCI_EXTENDED_MSG_CONT_LEN)
	{
		omcidbgPrintf(OMCI_DEBUG_LEVEL_ERROR, "[%s][%d]: contLen=%d is cross the border\n",__FUNCTION__,__LINE__,contLen);
		return OMCI_CMD_ERROR;
	}
	memset(responseContentPtr, 0, contLen);
	*responseContentPtr = resultAndResean;
	omciPayLoad->msgContentLength = (devId == OMCI_BASELINE_MSG) ? OMCI_BASELINE_CONT_LEN : 1;// 1 byte for resultAndReason
		
	omciPktSend(omciPayLoad, TRUE);
	omciDumpPkt(omciPayLoad);	

	omcidbgPrintf(OMCI_DEBUG_LEVEL_NO_MSG, "[%s][%d] [CFGUPLOAD] return\n", __FUNCTION__, __LINE__);

	return 0;			
}

#endif

